package com.seeyon.apps.commonExt.util;


import com.seeyon.cap4.form.exception.FormException;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.ConvertUtilsBean;
import org.apache.commons.beanutils.Converter;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

public class CommonUtilExt {

    @SafeVarargs
    public static <T> List<T> list(T...elements) {
        List<T> list = new ArrayList<>();
        Collections.addAll(list, elements);
        return list;
    }

    @SafeVarargs
    public static <T> Set<T> set(T...elements) {
        Set<T> set = new HashSet<>();
        Collections.addAll(set, elements);
        return set;
    }

    public static LocalDateTime toDatetime(String value, String pattern) {
        return LocalDateTime.parse(value, DateTimeFormatter.ofPattern(pattern));
    }
    public static LocalDateTime toDatetime(String value) {
        return toDatetime(value, "yyyy-MM-dd HH:mm:ss");
    }

    public static LocalDate toDate(String value, String pattern) {
        return LocalDate.parse(value, DateTimeFormatter.ofPattern(pattern));
    }
    public static LocalDate toDate(String value) {
        return toDate(value, "yyyy-MM-dd");
    }

    public static Date toDate(LocalDate value) {
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = value.atStartOfDay(zoneId);
        return Date.from(zdt.toInstant());
    }
    public static Date toDate(LocalDateTime value) {
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = value.atZone(zoneId);
        return Date.from(zdt.toInstant());
    }

    public static Map<String, Object> convertToMap(Object obj) {
        Map<String, Object> map = new HashMap<>();
        if (obj == null) {
            return map;
        }
        Class<?> clazz = obj.getClass();
        for (Field field : clazz.getDeclaredFields()) {
            field.setAccessible(true);
            try {
                map.put(field.getName(), field.get(obj));
            } catch (IllegalAccessException ignored) {
            }
        }
        return map;
    }

    public static Map<String, Object> convertToMapRecursive(Object obj) {
        Map<String, Object> resultMap = new HashMap<>();
        if (obj == null) {
            return resultMap;
        }

        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true); // 允许访问私有字段
            try {
                Object value = field.get(obj);
                if (value != null) {
                    if (isBasicType(value.getClass()) || value instanceof Map) {
                        resultMap.put(field.getName(), value);
                    } else {
                        resultMap.put(field.getName(), convertToMapRecursive(value));
                    }
                }
            } catch (IllegalAccessException ignored) {

            }
        }
        return resultMap;
    }

    private static boolean isBasicType(Class<?> clazz) {
        return clazz.isPrimitive() ||
                clazz.equals(String.class) ||
                clazz.equals(Integer.class) ||
                clazz.equals(Long.class) ||
                clazz.equals(Double.class) ||
                clazz.equals(Float.class) ||
                clazz.equals(Boolean.class) ||
                clazz.equals(Character.class) ||
                clazz.equals(Short.class) ||
                clazz.equals(Byte.class);
    }


    public static void copy(Object source, Object target) {
        try {
            // 使用自定义转换器
            BeanUtilsBean beanUtilsBean = BeanUtilsBean.getInstance();
            beanUtilsBean.copyProperties(target, source);
        } catch (Exception e) {
            throw new FormException(e.getMessage());
        }
    }

    public static void copyWithConvert(Object source, Object target) {
        try {
            // 使用自定义转换器
            BeanUtilsBean beanUtilsBean = BeanUtilsBean.getInstance();
            ConvertUtilsBean convertUtils = beanUtilsBean.getConvertUtils();
            convertUtils.register(new TimestampToLocalDateTimeConverter(), LocalDateTime.class);
            convertUtils.register(new TimestampToLocalDateConverter(), LocalDate.class);
            beanUtilsBean.copyProperties(target, source);
        } catch (Exception e) {
            throw new FormException(e.getMessage());
        }
    }


    public static class TimestampToLocalDateTimeConverter implements Converter {
        @Override
        public Object convert(Class aClass, Object value) {
            if (value == null) {
                return value;
            }
            if (StringUtils.isBlank(value.toString())) {
                return null;
            }
            if (!(value instanceof Timestamp)) {
                return value;
            }
            Timestamp timestamp = (Timestamp) value;
            return timestamp.toLocalDateTime();
        }
    }
    public static class TimestampToLocalDateConverter implements Converter {
        @Override
        public Object convert(Class aClass, Object value) {
            if (value == null) {
                return value;
            }
            if (StringUtils.isBlank(value.toString())) {
                return null;
            }
            if (!(value instanceof Timestamp)) {
                return value;
            }
            Timestamp timestamp = (Timestamp) value;
            LocalDateTime localDateTime = timestamp.toLocalDateTime();
            return localDateTime.toLocalDate();
        }
    }
}
